home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / wnos / wn941101 / iproute.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-01  |  20.3 KB  |  740 lines

  1. /* Lower half of IP, consisting of gateway routines
  2.  * Includes routing and options processing code
  3.  *
  4.  * changed the ip.tos test so that it always uses
  5.  * VC mode and Never DA mode. dc0hk.940920
  6.  * 
  7.  * Added IPaccess control     dc0hk.941001
  8.  *
  9.  */
  10. #include "global.h"
  11. #include "mbuf.h"
  12. #include "iface.h"
  13. #include "timer.h"
  14. #include "internet.h"
  15. #include "ip.h"
  16. #include "netuser.h"
  17. #include "icmp.h"
  18. #include "trace.h"
  19. #include "pktdrvr.h"
  20. #include "files.h"
  21. #include "config.h"
  22.  
  23. #define    RIP_INFINITY    16
  24.  
  25. extern void rt_timeout __ARGS((void *s));
  26.  
  27. struct route *Routes[32][HASHMOD];    /* Routing table */
  28. struct route R_default = {            /* Default route entry */
  29.     NULLROUTE, NULLROUTE,
  30.     0,0,0,
  31.     RIP_INFINITY                    /* Init metric to infinity */
  32. };
  33.  
  34. int32 Ip_addr;
  35. static struct rt_cache Rt_cache;
  36.  
  37. #ifdef IPACCESS
  38. #define NETBITS(bits) ((bits) == 0 ? 0 : (~0L << (32 - bits)))
  39. struct rtaccess *IPaccess = NULLACCESS; /* access list */
  40. #endif
  41.  
  42. /* Initialize modulo lookup table used by hash_ip() in pcgen.asm */
  43. void
  44. ipinit()
  45. {
  46.     int i;
  47.  
  48.     for(i = 0; i < 256; i++)
  49.         Hashtab[i] = i % HASHMOD;
  50. }
  51.  
  52.  
  53. /* Route an IP datagram. This is the "hopper" through which all IP datagrams,
  54.  * coming or going, must pass.
  55.  *
  56.  * "rxbroadcast" is set to indicate that the packet came in on a subnet
  57.  * broadcast. The router will kick the packet upstairs regardless of the
  58.  * IP destination address.
  59.  */
  60. int
  61. ip_route(i_iface,r_iface,bp,rxbroadcast)
  62. struct iface *i_iface;            /* Input interface */
  63. struct iface *r_iface;            /* Iface to route */
  64. struct mbuf *bp;            /* Input packet */
  65. int rxbroadcast;            /* True if packet had link broadcast address */
  66. {
  67.     struct ip ip;            /* IP header being processed */
  68.     int16 ip_len;            /* IP header length */
  69.     int16 length;            /* Length of data portion */
  70.     int32 gateway;            /* Gateway IP address */
  71.     struct route *rp;        /* Route table entry */
  72.     struct iface *iface;        /* Output interface, possibly forwarded */
  73.     int16 offset;            /* Offset into current fragment */
  74.     int16 mf_flag;            /* Original datagram MF flag */
  75.     int strict = 0;            /* Strict source routing flag */
  76.     char prec;            /* Extracted from tos field */
  77.     char del;
  78.     char tput;
  79.     char rel;
  80.     int16 opt_len;            /* Length of current option */
  81.     char *opt;            /* -> beginning of current option */
  82.     char *ptr;            /* -> pointer field in source route fields */
  83.     struct mbuf *tbp;
  84.     int ckgood = 1;
  85. #ifdef IPACCESS
  86.     int16 srcport, dstport; /* for use in access checking */
  87.     struct rtaccess *tpacc; /* temporary for access checking */
  88. #endif
  89.     int pointer;        /* Relative pointer index for sroute/rroute */
  90.  
  91.     if(i_iface != NULLIF){
  92.         ipInReceives++;            /* Not locally generated */
  93.         i_iface->iprecvcnt++;
  94.     }
  95.     if(len_p(bp) < IPLEN){
  96.         /* The packet is shorter than a legal IP header */
  97.         ipInHdrErrors++;
  98.         free_p(bp);
  99.         return -1;
  100.     }
  101.     /* Sneak a peek at the IP header's IHL field to find its length */
  102.     ip_len = (bp->data[0] & 0xf) << 2;
  103.     if(ip_len < IPLEN){
  104.         /* The IP header length field is too small */
  105.         ipInHdrErrors++;
  106.         free_p(bp);
  107.         return -1;
  108.     }
  109.     if(cksum(NULLHEADER,bp,ip_len) != 0){
  110.         /* Bad IP header checksum; discard */
  111.         ipInHdrErrors++;
  112.         free_p(bp);
  113.         return -1;
  114.     }
  115.     /* Extract IP header */
  116.     ntohip(&ip,&bp);
  117.  
  118.     if(ip.version != IPVERSION){
  119.         /* We can't handle this version of IP */
  120.         ipInHdrErrors++;
  121.         free_p(bp);
  122.         return -1;
  123.     }
  124.     /* Trim data segment if necessary. */
  125.     length = ip.length - ip_len;    /* Length of data portion */
  126.     trim_mbuf(&bp,length);
  127.  
  128.     /* If we're running low on memory, return a source quench */
  129.     if(!rxbroadcast && availmem() < Memthresh)
  130.         icmp_output(&ip,bp,ICMP_QUENCH,0,NULLICMP);
  131.  
  132.     /* Process options, if any. Also compute length of secondary IP
  133.      * header in case fragmentation is needed later
  134.      */
  135.     strict = 0;
  136.     for(opt = ip.options; opt < &ip.options[ip.optlen];opt += opt_len){
  137.         /* Most options have a length field. If this is a EOL or NOOP,
  138.          * this (garbage) value won't be used
  139.          */
  140.         opt_len = uchar(opt[1]);
  141.  
  142.         switch(opt[0] & OPT_NUMBER){
  143.         case IP_EOL:
  144.             goto no_opt;    /* End of options list, we're done */
  145.         case IP_NOOP:
  146.             opt_len = 1;
  147.             break;        /* No operation, skip to next option */
  148.         case IP_SSROUTE:    /* Strict source route & record route */
  149.             strict = 1;    /* note fall-thru */
  150.         case IP_LSROUTE:    /* Loose source route & record route */
  151.             /* Source routes are ignored unless we're in the
  152.              * destination field
  153.              */
  154.             if(ismyaddr(ip.dest) == NULLIF)
  155.                 break;    /* Skip to next option */
  156.             if(uchar(opt[2]) >= opt_len){
  157.                 break;    /* Route exhausted; it's for us */
  158.             }
  159.             /* Put address for next hop into destination field,
  160.              * put our address into the route field, and bump
  161.              * the pointer
  162.              */
  163.             ptr = opt + uchar(opt[2]) - 1;
  164.             ip.dest = get32(ptr);
  165.             put32(ptr,locaddr(ip.dest));
  166.             opt[2] += 4;
  167.             ckgood = 0;
  168.             break;
  169.         case IP_RROUTE:    /* Record route */
  170.             if(uchar(opt[2]) > opt_len - 3){
  171.                 /* Route area exhausted; kick back an error */
  172.                 if(!rxbroadcast){
  173.                     union icmp_args icmp_args;
  174.  
  175.                     icmp_args.pointer = IPLEN + opt - ip.options;
  176.                     icmp_output(&ip,bp,ICMP_PARAM_PROB,0,&icmp_args);
  177.                 }
  178.                 free_p(bp);
  179.                 return -1;
  180.             }
  181.             /* Add our address to the route */
  182.             ptr = opt + uchar(opt[2]) - 1;
  183.             ptr = put32(ptr,locaddr(ip.dest));
  184.             opt[2] += 4;
  185.             ckgood = 0;
  186.             break;
  187.         }
  188.     }
  189. no_opt:
  190.  
  191.     /* See if it's a broadcast or addressed to us, and kick it upstairs */
  192.     if(ismyaddr(ip.dest) != NULLIF || rxbroadcast){
  193.         if(r_iface != NULLIF)
  194.             rt_add(ip.source,32,0,r_iface,1,0,3);        /* TEST */
  195. #ifdef    GWONLY
  196.     /* We're only a gateway, we have no host level protocols */
  197.         if(!rxbroadcast)
  198.             icmp_output(&ip,bp,ICMP_DEST_UNREACH,ICMP_PROT_UNREACH,NULLICMP);
  199.         ipInUnknownProtos++;
  200.         free_p(bp);
  201. #else
  202.         ip_recv(i_iface,&ip,bp,rxbroadcast);
  203. #endif
  204.         return 0;
  205.     }
  206.     /* Packet is not destined to us. If it originated elsewhere, count
  207.      * it as a forwarded datagram.
  208.      */
  209.     if(i_iface != NULLIF)
  210.         ipForwDatagrams++;
  211.  
  212.     /* Adjust the header checksum to allow for the modified TTL */
  213.     ip.checksum += 0x100;
  214.     if((ip.checksum & 0xff00) == 0)
  215.         ip.checksum++;    /* end-around carry */
  216.  
  217.     /* Decrement TTL and discard if zero. We don't have to check
  218.      * rxbroadcast here because it's already been checked
  219.      */
  220.     if(--ip.ttl == 0){
  221.         /* Send ICMP "Time Exceeded" message */
  222.         icmp_output(&ip,bp,ICMP_TIME_EXCEED,0,NULLICMP);
  223.         ipInHdrErrors++;
  224.         free_p(bp);
  225.         return -1;
  226.     }
  227.     /* Look up target address in routing table */
  228.     if((rp = rt_lookup(ip.dest)) == NULLROUTE){
  229.         /* No route exists, return unreachable message (we already
  230.          * know this can't be a broadcast)
  231.          */
  232.         icmp_output(&ip,bp,ICMP_DEST_UNREACH,ICMP_HOST_UNREACH,NULLICMP);
  233.         free_p(bp);
  234.         ipOutNoRoutes++;
  235.         return -1;
  236.     }
  237.     rp->uses++;
  238.     /* Check for output forwarding and divert if necessary */
  239.     iface = rp->iface;
  240.     if(iface->forw != NULLIF)
  241.         iface = iface->forw;
  242.  
  243.   
  244. #ifdef IPACCESS
  245. /* At this point we've decided to send the packet out 'iface' (unless it
  246. won't fragment).  Check ip.protocol for tcp or udp.
  247. Should probably have counter on number of dropped packets.
  248. */
  249.     if((ip.protocol == TCP_PTCL) || (ip.protocol==UDP_PTCL)) {
  250.         /* pull up source & destination port */
  251.         srcport = get16(&(bp->data[0])); /*done for futures & debug*/
  252.         dstport = get16(&(bp->data[2]));
  253.     }
  254.     /* for backwards compatibility, if there are *no* entries */
  255.     /* we ignore access control, so everything is legal. Any  */
  256.     /* entry for an iface means default is to drop if no      */
  257.     /* permission found  */
  258.     for( tpacc = IPaccess;tpacc != NULLACCESS;tpacc=tpacc->nxtiface) {
  259.         /*find a matching iface*/
  260.         if(tpacc->iface == iface ){ /* Needs to be authorized */
  261.             if(!ip_check(tpacc, ip.protocol, ip.source, ip.dest, dstport))
  262.                 break;
  263.             /* not found, throw it away. */
  264.             /* if NO access, then drop & increment counter */
  265.             /* see new(er) RFC for proper ICMP codes */
  266.             /* maybe counter is in MIB? else create.*/
  267.             icmp_output(&ip,bp,ICMP_DEST_UNREACH,ICMP_HOST_UNREACH,NULLICMP);
  268.             ipOutNoRoutes++;
  269.             free_p(bp);
  270.             return -1;
  271.         }
  272.     }
  273. #endif
  274.  
  275.     /* Find gateway; zero gateway in routing table means "send direct" */
  276.     gateway = (rp->gateway == 0) ? ip.dest : rp->gateway;
  277.  
  278.     if(strict && gateway != ip.dest) {
  279.         /* Strict source routing requires a direct entry
  280.          * Again, we know this isn't a broadcast
  281.          */
  282.         icmp_output(&ip,bp,ICMP_DEST_UNREACH,ICMP_ROUTE_FAIL,NULLICMP);
  283.         free_p(bp);
  284.         ipOutNoRoutes++;
  285.         return -1;
  286.     }
  287.     prec = PREC(ip.tos);
  288.     del  = ip.tos & DELAY;          
  289.     tput = ip.tos & THRUPUT;        
  290.     rel  = ip.tos & RELIABILITY;    
  291.  
  292.     if(ip.length <= ip_mtu(gateway)) { /* TEST */
  293. /*    if(ip.length <= iface->mtu) { */
  294.         /* Datagram smaller than interface MTU; put header
  295.          * back on and send normally. Recompute header checksum
  296.          * because we modified the TTL.
  297.          */
  298.         if((tbp = htonip(&ip,bp,ckgood)) == NULLBUF){
  299.             free_p(bp);
  300.             return -1;
  301.         }
  302.         iface->ipsndcnt++;
  303.         return (*iface->send)(tbp,iface,gateway,prec,del,tput,rel);
  304.     }
  305.     /* Fragmentation needed */
  306.     if(ip.flags.df){
  307.         /* Don't Fragment set; return ICMP message and drop */
  308.         union icmp_args icmp_args;
  309.  
  310.         icmp_args.mtu = iface->mtu;
  311.         icmp_output(&ip,bp,ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED,&icmp_args);
  312.         free_p(bp);
  313.         ipFragFails++;
  314.         return -1;
  315.     }
  316.     /* Create fragments */
  317.     offset = ip.offset;
  318.     mf_flag = ip.flags.mf;        /* Save original MF flag */
  319.     while(length != 0){        /* As long as there's data left */
  320.         int16 fragsize;        /* Size of this fragment's data */
  321.         struct mbuf *f_data;    /* Data portion of fragment */
  322.  
  323.         /* After the first fragment, should remove those
  324.          * options that aren't supposed to be copied on fragmentation
  325.          */
  326.         ip.offset = offset;
  327.         if(length + ip_len <= iface->mtu){
  328.             /* Last fragment; send all that remains */
  329.             fragsize = length;
  330.             ip.flags.mf = mf_flag;    /* Pass original MF flag */
  331.         } else {
  332.             /* More to come, so send multiple of 8 bytes */
  333.             fragsize = (iface->mtu - ip_len) & 0xfff8;
  334.             ip.flags.mf = 1;
  335.         }
  336.         ip.length = fragsize + ip_len;
  337.  
  338.         /* Duplicate the fragment */
  339.         dup_p(&f_data,bp,offset,fragsize);
  340.         if(f_data == NULLBUF){
  341.             free_p(bp);
  342.             ipFragFails++;
  343.             return -1;
  344.         }
  345.         /* Put IP header back on, recomputing checksum */
  346.         if((tbp = htonip(&ip,f_data,0)) == NULLBUF){
  347.             free_p(f_data);
  348.             free_p(bp);
  349.             ipFragFails++;
  350.             return -1;
  351.         }
  352.         /* and ship it out */
  353.         if((*iface->send)(tbp,iface,gateway,prec,del,tput,rel) == -1){
  354.             ipFragFails++;
  355.             free_p(bp);
  356.             return -1;
  357.         }
  358.         iface->ipsndcnt++;
  359.         ipFragCreates++;
  360.         offset += fragsize;
  361.         length -= fragsize;
  362.     }
  363.     ipFragOKs++;
  364.     free_p(bp);
  365.     return 0;
  366. }
  367.  
  368. int
  369. ip_encap(bp,iface,gateway,prec,del,tput,rel)
  370. struct mbuf *bp;
  371. struct iface *iface;
  372. int32 gateway;
  373. int prec;
  374. int del;
  375. int tput;
  376. int rel;
  377. {
  378.     struct ip ip;
  379.  
  380.     dump(iface,IF_TRACE_OUT,CL_NONE,bp);
  381.  
  382.     if(gateway == 0L){
  383.         /* Gateway must be specified */
  384.         ntohip(&ip,&bp);
  385.         icmp_output(&ip,bp,ICMP_DEST_UNREACH,ICMP_HOST_UNREACH,NULLICMP);
  386.         free_p(bp);
  387.         ipOutNoRoutes++;
  388.         return -1;
  389.     }
  390.     /* Encapsulate in an IP packet from us to the gateway */
  391.     return ip_send(INADDR_ANY,gateway,IP_PTCL,0,0,bp,0,0,0);
  392. }
  393.  
  394. /* Add an entry to the IP routing table. Returns 0 on success, -1 on failure */
  395. struct route *
  396. rt_add(target,bits,gateway,iface,metric,ttl,private)
  397. int32 target;            /* Target IP address prefix */
  398. unsigned int bits;        /* Size of target address prefix in bits (0-32) */
  399. int32 gateway;            /* Optional gateway to be reached via interface */
  400. struct iface *iface;    /* Interface to which packet is to be routed */
  401. int32 metric;            /* Metric for this route entry */
  402. int32 ttl;                /* Lifetime of this route entry in sec */
  403. char private;            /* Inhibit advertising this entry ? */
  404. {
  405.     struct route *rp, **hp, *rptmp;
  406.     int32 gwtmp;
  407.  
  408.     if(iface == NULLIF)
  409.         return NULLROUTE;
  410.  
  411.     if(bits == 32 && ismyaddr(target))
  412.         return NULLROUTE;    /* Don't accept routes to ourselves */
  413.  
  414.     if(bits > 32)
  415.         bits = 32;
  416.  
  417.     /* Encapsulated routes must specify gateway, and it can't be
  418.      *  ourselves
  419.      */
  420.     if(iface == &Encap && (gateway == 0 || ismyaddr(gateway)))
  421.         return NULLROUTE;
  422.  
  423.     Rt_cache.route = NULLROUTE;    /* Flush cache */
  424.  
  425.     target &= (~0L << (32 - bits));
  426.  
  427.     /* Zero bits refers to the default route */
  428.     if((rp = (bits == 0) ? &R_default : rt_blookup(target,bits)) == NULLROUTE) {
  429.         /* The target is not already in the table, so create a new
  430.          * entry and put it in.
  431.          */
  432.         rp = (struct route *)mxallocw(sizeof(struct route));
  433.         /* Insert at head of table */
  434.         rp->prev = NULLROUTE;
  435.         hp = &Routes[bits-1][hash_ip(target)];
  436.         rp->next = *hp;
  437.         if(rp->next != NULLROUTE)
  438.             rp->next->prev = rp;
  439.         *hp = rp;
  440.         rp->uses = 0;
  441.     }
  442.     if(rp->flags != RTPRIVATE) {
  443.         rp->target = target;
  444.         rp->bits = bits;
  445.         rp->gateway = gateway;
  446.         rp->metric = metric;
  447.         rp->iface = iface;
  448.         if(private != 3)
  449.             /* Should anyone be told of this route? */
  450.             rp->flags = private ? RTPRIVATE : 0;
  451.     }
  452.     rp->timer.func = rt_timeout;  /* Set the timer field */
  453.     rp->timer.arg = (void *)rp;
  454.     set_timer(&rp->timer,ttl*1000L);
  455.     stop_timer(&rp->timer);
  456.     start_timer(&rp->timer); /* start the timer if appropriate */
  457.  
  458.     /* Check to see if this created an encapsulation loop */
  459.     gwtmp = gateway;
  460.     for(;;){
  461.         rptmp = rt_lookup(gwtmp);
  462.         if(rptmp == NULLROUTE)
  463.             break;    /* No route to gateway, so no loop */
  464.         if(rptmp->iface != &Encap)
  465.             break;    /* Non-encap interface, so no loop */
  466.         if(rptmp == rp){
  467.             rt_drop(target,bits);    /* Definite loop */
  468.             return NULLROUTE;
  469.         }
  470.         if(rptmp->gateway != 0)
  471.             gwtmp = rptmp->gateway;
  472.     }
  473.     return rp;
  474. }
  475.  
  476. /* Remove an entry from the IP routing table. Returns 0 on success, -1
  477.  * if entry was not in table.
  478.  */
  479. int
  480. rt_drop(target,bits)
  481. int32 target;
  482. unsigned int bits;
  483. {
  484.     struct route *rp;
  485.  
  486.     Rt_cache.route = NULLROUTE;    /* Flush the cache */
  487.  
  488.     if(bits == 0){
  489.         /* Nail the default entry */
  490.         stop_timer(&R_default.timer);
  491.         R_default.iface = NULLIF;
  492.         return 0;
  493.     }
  494.     if(bits > 32)
  495.         bits = 32;
  496.  
  497.     /* Mask off target according to width */
  498.     target &= ~0L << (32-bits);
  499.  
  500.     /* Search appropriate chain for existing entry */
  501.     for(rp = Routes[bits-1][hash_ip(target)];rp != NULLROUTE;rp = rp->next){
  502.         if(rp->target == target)
  503.             break;
  504.     }
  505.     if(rp == NULLROUTE)
  506.         return -1;    /* Not in table */
  507.  
  508.     stop_timer(&rp->timer);
  509.     if(rp->next != NULLROUTE)
  510.         rp->next->prev = rp->prev;
  511.     if(rp->prev != NULLROUTE)
  512.         rp->prev->next = rp->next;
  513.     else
  514.         Routes[bits-1][hash_ip(target)] = rp->next;
  515.  
  516.     xfree((char *)rp);
  517.     return 0;
  518. }
  519.  
  520. #ifndef    GWONLY
  521. /* Given an IP address, return the MTU of the local interface used to
  522.  * reach that destination. This is used by TCP to avoid local fragmentation
  523.  */
  524. int16
  525. ip_mtu(addr)
  526. int32 addr;
  527. {
  528.     struct route *rp;
  529.     struct iface *iface;
  530.  
  531.     if((rp = rt_lookup(addr)) == NULLROUTE || rp->iface == NULLIF)
  532.         return 0;
  533.  
  534.     iface = rp->iface;
  535.  
  536.     return (iface->forw == NULLIF) ? iface->mtu : iface->forw->mtu;
  537. }
  538. /* Given a destination address, return the IP address of the local
  539.  * interface that will be used to reach it. If there is no route
  540.  * to the destination, pick the first non-loopback address.
  541.  */
  542. int32
  543. locaddr(addr)
  544. int32 addr;
  545. {
  546.     struct route *rp;
  547.     struct iface *ifp;
  548.  
  549.     if(ismyaddr(addr) != NULLIF)
  550.         return addr;    /* Loopback case */
  551.  
  552.     if((rp = rt_lookup(addr)) != NULLROUTE && rp->iface != NULLIF)
  553.         ifp = rp->iface;
  554.     else {
  555.         for(ifp = Ifaces;ifp != NULLIF;ifp = ifp->next){
  556.             if(ifp != &Loopback)
  557.                 break;
  558.         }
  559.     }
  560.     if(ifp == NULLIF || ifp == &Loopback)
  561.         return 0;    /* No dice */
  562.  
  563.     if(ifp == &Encap){
  564.         /* Recursive call - we assume that there are no circular
  565.          * encapsulation references in the routing table!!
  566.          * (There is a check at the end of rt_add() that goes to
  567.          * great pains to ensure this.)
  568.          */
  569.         if(Encap.addr != 0)
  570.             return Encap.addr;
  571.  
  572.         return locaddr(rp->gateway);
  573.     }
  574.     return (ifp->forw == NULLIF) ? ifp->addr : ifp->forw->addr;
  575. }
  576. #endif
  577. /* Look up target in hash table, matching the entry having the largest number
  578.  * of leading bits in common. Return default route if not found;
  579.  * if default route not set, return NULLROUTE
  580.  */
  581. struct route *
  582. rt_lookup(target)
  583. int32 target;
  584. {
  585.     struct route *rp;
  586.     int bits;
  587.     int32 tsave, mask;
  588.  
  589.     /* Examine cache first */
  590.     if(target == Rt_cache.target && Rt_cache.route != NULLROUTE)
  591.         return Rt_cache.route;
  592.  
  593.     tsave = target;
  594.  
  595.     mask = ~0;    /* All ones */
  596.     for(bits = 31; bits >= 0; bits--){
  597.         target &= mask;
  598.         for(rp = Routes[bits][hash_ip(target)];rp != NULLROUTE;rp = rp->next){
  599.             if(rp->target == target){
  600.                 /* Stash in cache and return */
  601.                 Rt_cache.target = tsave;
  602.                 Rt_cache.route = rp;
  603.                 return rp;
  604.             }
  605.         }
  606.         mask <<= 1;
  607.     }
  608.     if(R_default.iface != NULLIF){
  609.         Rt_cache.target = tsave;
  610.         Rt_cache.route = &R_default;
  611.         return &R_default;
  612.     } else
  613.         return NULLROUTE;
  614. }
  615. /* Search routing table for entry with specific width */
  616. struct route *
  617. rt_blookup(target,bits)
  618. int32 target;
  619. unsigned int bits;
  620. {
  621.     struct route *rp;
  622.  
  623.     if(bits == 0) {
  624.         if(R_default.iface != NULLIF)
  625.             return &R_default;
  626.         else
  627.             return NULLROUTE;    /* No default route */
  628.     }
  629.     /* Mask off target according to width */
  630.     target &= ~0L << (32-bits);
  631.  
  632.     for(rp = Routes[bits-1][hash_ip(target)];rp != NULLROUTE;rp = rp->next){
  633.         if(rp->target == target){
  634.             return rp;
  635.         }
  636.     }
  637.     return NULLROUTE;
  638. }
  639.  
  640. #ifdef XXX
  641. /* Scan the routing table. For each entry, see if there's a less-specific
  642.  * one that points to the same interface and gateway. If so, delete
  643.  * the more specific entry, since it is redundant.
  644.  */
  645. static void
  646. rt_merge(trace)
  647. int trace;
  648. {
  649.     int bits,i,j;
  650.     struct route *rp,*rpnext,*rp1;
  651.  
  652.     for(bits=32;bits>0;bits--){
  653.         for(i = 0;i<HASHMOD;i++){
  654.             for(rp = Routes[bits-1][i];rp != NULLROUTE;rp = rpnext){
  655.                 rpnext = rp->next;
  656.                 for(j=bits-1;j >= 0;j--){
  657.                     if((rp1 = rt_blookup(rp->target,j)) != NULLROUTE
  658.                      && rp1->iface == rp->iface
  659.                      && rp1->gateway == rp->gateway){
  660.                         if(trace > 1)
  661.                             tprintf("merge %s %d\n",
  662.                              inet_ntoa(rp->target),
  663.                              rp->bits);
  664.                         rt_drop(rp->target,rp->bits);
  665.                         break;
  666.                     }
  667.                 }
  668.             }
  669.         }
  670.     }
  671. }
  672. #endif
  673.   
  674. #ifdef IPACCESS
  675. /* check to see if packet is "authorized".  Returns 0 if matching */
  676. /* permit record is found, -1 if not found or deny record found */
  677. int
  678. ip_check(accptr,protocol,src,dest,port)
  679. struct rtaccess *accptr;
  680. int16 protocol,port;
  681. int32 src,dest;
  682. {
  683.     int32 smask,tmask;
  684.   
  685.     for(;accptr != NULLACCESS;accptr = accptr->nxtbits) {
  686.         if ((accptr->protocol == 0) ||
  687.         (accptr->protocol == protocol)) {
  688.             smask = NETBITS(accptr->sbits);
  689.             tmask = NETBITS(accptr->bits);
  690.             if ((accptr->source == (smask & src)) &&
  691.                 (accptr->target == (tmask & dest)) &&
  692.                 ((accptr->lowport == 0) ||
  693.                 ((port >= accptr->lowport) &&
  694.             (port <= accptr->highport)))) {
  695.                 return (accptr->status);
  696.             }
  697.         }
  698.     }
  699.     return -1; /* fall through to here if not found */
  700. }
  701. /* add an entry to the access control list */
  702. /* not a lot of error checking 8-) */
  703. void
  704. addaccess(protocol,source,sbits,target,tbits,ifp,low,high,permit)
  705. int16 protocol;         /* IP protocol */
  706. int32 source,target;        /* Source & target IP address prefix */
  707. unsigned int sbits,tbits;   /* Size of address prefix in bits (0-32) */
  708. struct iface *ifp;      /* Interface to which packet may be routed */
  709. int16 low;
  710. int16 high;
  711. int16 permit;
  712. {
  713.     struct rtaccess *tpacc; /*temporary*/
  714.     struct rtaccess *holder; /*for the new record*/
  715.   
  716.     holder = (struct rtaccess *)mxallocw(sizeof(struct rtaccess));
  717.     holder->nxtiface = NULLACCESS;
  718.     holder->nxtbits = NULLACCESS;
  719.     holder->protocol = protocol;
  720.     holder->source = source;
  721.     holder->sbits = sbits;
  722.     holder->target = target;
  723.     holder->bits = tbits;
  724.     holder->iface = ifp;
  725.     holder->lowport = low;
  726.     holder->highport = high;
  727.     holder->status = permit;
  728.     for(tpacc = IPaccess;tpacc != NULLACCESS;tpacc = tpacc->nxtiface)
  729.         if(tpacc->iface == ifp) { /* get to end */
  730.             while(tpacc->nxtbits != NULLACCESS)
  731.                 tpacc = tpacc->nxtbits;
  732.             tpacc->nxtbits = holder;
  733.             return;
  734.         }
  735.   /* iface wasn't found, so just add at head of list */
  736.     holder->nxtiface = IPaccess;
  737.     IPaccess = holder;
  738. }
  739. #endif
  740.